---
title: Event
keywords:
  - event
  - unit
  - message
  - command
  - событие
  - юнит
  - сообщение
  - команда
description: Event API, его методы, свойства и примеры использования
lang: ru
---

import Tabs from "@components/Tabs/Tabs.astro";
import TabItem from "@components/Tabs/TabItem.astro";

# Event API (#event-api)

```ts
import { type Event, type EventCallable, createEvent } from "effector";

const event = createEvent();
```

Событие в effector представляет действие пользователя, шаг в процессе приложения, команду к выполнению или намерение внести изменения и многое другое. <br/>
Событие служит как точка входа в реактивный поток данных — простой способ сказать приложению "что-то произошло".

:::tip{title="это ваше каноничное событие"}
Если вы не знакомы с событиями и способами работы с ними, то вам сюда [Что такое события и как работать с ними](/ru/essentials/events).
:::

## Типы событий (#event-types)

Важно понять, что существуют два типа событий:

1. **Обычное событие**, которое создается с помощью [`createEvent`](/ru/api/effector/createEvent), [`.prepend`](/ru/api/effector/Event#eventCallable-methods-prepend-fn); эти события имеют тип [`EventCallable`](/ru/essentials/typescript#event-types) и могут быть вызваны, либо использованы в [`target`](/ru/essentials/unit-composition#sample) метода [`sample`](/ru/essentials/unit-composition).
2. **Производное событие**, который создается с помощью [`.map`](#event-methods-map-fn), [`.filter`](#event-methods-filter-fn), [`.filterMap`](#event-methods-filterMap-fn). Такие события имеют тип [`Event`](/ru/essentials/typescript#event-types) и их **нельзя вызывать или передавать в [`target`](/ru/essentials/unit-composition#sample)**, effector сам вызовет их в нужном порядке, однако вы можете подписываться на эти события с помощью [`sample`](/ru/essentials/unit-composition) или [`watch`](#event-methods-watch-watcher).

## Интерфейс Event (#event-interface)

Доступные методы и свойства событий:

| <div style="width:170px">Метод/Свойство</div>                            | Описание                                                                                                       |
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| [`prepend(fn)`](/ru/api/effector/Event#eventCallable-methods-prepend-fn) | Создаёт новое событие `EventCallable`, трансформируют входные данные через `fn` и передает в исходное событие. |
| [`map(fn)`](#event-methods-map-fn)                                       | Создаёт новое событие типа `Event` с результатом вызова `fn` после срабатывания исходного события.             |
| [`filter({fn})` ](#event-methods-filter-fn)                              | Создаёт новое событие типа `Event`, срабатывающий только если `fn` возвращает `true`.                          |
| [`filterMap(fn)`](#event-methods-filterMap-fn)                           | Создаёт событие типа `Event`, срабатывающий с результатом `fn`, если тот не вернул `undefined`.                |
| [`watch(watcher)`](#event-methods-watch-watcher)                         | Добавляет слушатель, вызывающий `watcher` при каждом срабатывании события.                                     |
| [`subscribe(observer)`](#event-methods-subscribe-observer)               | Низкоуровневый метод для интеграции события со стандартным шаблоном `Observable`.                              |
| [`sid`](#event-properties-sid)                                           | Уникальный идентификатор юнита (`unit`).                                                                       |
| [`shortName`](#event-properties-shortName)                               | Свойство типа `string`, содержащее имя переменной, в которой объявлено событие.                                |
| [`compositeName`](#event-properties-compositeName)                       | Комплексное имя Event (включая домен и короткое имя) — удобно для логирования и трассировки.                   |

## Методы событий (#event-methods)

### `.prepend(fn)` (#eventCallable-methods-prepend-fn)

:::info{title="информация"}
Этот метод существует **только** для обычных событий (`EventCallable`)! Это значит что этот метод может использоваться только на событиях созданных с помощью [`createEvent`](/ru/api/effector/createEvent).
:::

Создает новое событие `EventCallable`, который можно вызвать. При его срабатывании вызвает `fn` и передает преобразованные данные в исходное событие.

- **Формула**

```ts
const second = first.prepend(fn);
```

- **Тип**

```ts
event.prepend<Before = void>(
  fn: (_: Before) => Payload
): EventCallable<Before>
```

- **Примеры**

```ts
import { createEvent } from "effector";

// исходное событие
const userPropertyChanged = createEvent();

const changeName = userPropertyChanged.prepend((name) => ({
  field: "name",
  value: name,
}));
const changeRole = userPropertyChanged.prepend((role) => ({
  field: "role",
  value: role.toUpperCase(),
}));

userPropertyChanged.watch(({ field, value }) => {
  console.log(`Свойство пользователя "${field}" изменилось на ${value}`);
});

changeName("john");
// => Свойство пользователя "name" изменилось на john

changeRole("admin");
// => Свойство пользователя "role" изменилось на ADMIN

changeName("alice");
// => Свойство пользователя "name" изменилось на alice
```

[Открыть пример](https://share.effector.dev/XGxlG4LD)

Вы можете считать этот метод функцией-обёрткой. Допустим, у нас есть функция с неидеальным API, но нам нужно часто её вызывать:

```ts
import { sendAnalytics } from "./analytics";

export function reportClick(item: string) {
  const argument = { type: "click", container: { items: [arg] } };
  return sendAnalytics(argument);
}
```

Это именно то, как работает `.prepend()`:

```ts
import { sendAnalytics } from "./analytics";

export const reportClick = sendAnalytics.prepend((item: string) => {
  return { type: "click", container: { items: [arg] } };
});

reportClick("example");
// reportClick сработал "example"
// sendAnalytics сработал с { type: "click", container: { items: ["example"] } }
```

- **Детальное описание**

Работает как обратный [`.map`](#event-methods-map-fn). В случае `.prepend` данные преобразуются **до срабатывания** исходного события, а в случае [`.map`](#event-methods-map-fn) данные преобразуются **после срабатывания**.

Если исходное событие принадлежит какому-либо [домену](/ru/api/effector/Domain), то новое событие также будет ему принадлежать.

- **Возвращаемое значение**

Возвращает новое событие `EventCallable`.

Ознакомьтесь со всеми другими методами в [Event](#event-methods).

---

### `.map(fn)` (#event-methods-map-fn)

Создает новое производное событие, которое будет вызвано после того, как будет вызвано исходное событие, используя результат функции `fn` в качестве его аргумента.

:::info{title="Чистота наше все!"}
Функция `fn` **должна быть чистой**.
:::

- **Формула**

```ts
// Событие любого типа, как производное так и обычное
const first: Event<T> | EventCallable<T>;
const second: Event<F> = first.map(fn);
```

- **Тип**

```ts
event.map<T>(fn: (payload: Payload) => T): Event<T>
```

- **Примеры**

```ts
import { createEvent } from "effector";

const userUpdated = createEvent<{ name: string; role: string }>();

// вы можете разбить поток данных с помощью метода .map()
const userNameUpdated = userUpdated.map(({ user }) => name);

// либо преобразовать данные
const userRoleUpdated = userUpdated.map((user) => user.role.toUpperCase());

userNameUpdated.watch((name) => console.log(`Имя пользователя теперь [${name}]`));
userRoleUpdated.watch((role) => console.log(`Роль пользователя теперь [${role}]`));

userUpdated({ name: "john", role: "admin" });
// => Имя пользователя теперь [john]
// => Роль пользователя теперь [ADMIN]
```

[Открыть пример](https://share.effector.dev/duDut6nR)

- **Детальное описание**

Метод `.map` позволяет вам разбивать и управлять потоком данных, а также извлекать или преобразовывать данные в рамках вашей модели бизнес-логики.

- **Возвращаемое значение**

Возвращает новое производное событие.

---

### `.filter({ fn })` (#event-methods-filter-fn)

:::tip{title="совет"}
[`sample`](/ru/api/effector/sample) с аргументом `filter` является предпочтительным методом фильтрации:

```ts
const event = createEvent();

const filteredEvent = sample({
  clock: event,
  filter: () => true,
});
```

:::

Метод `.filter` генерирует новое производное событие, которое будет вызвано после исходного события,в случае если функция `fn` вернет `true`. Эта специальная функция позволяет вам разбить поток данных на ветви и подписаться на них в рамках модели бизнес-логики.<br />
Это очень удобно, если мы хотим на события которые срабатывают по условию.

- **Формула**

```ts
// Событие любого типа, как производное так и обычное
const first: Event<T> | EventCallable<T>;
const second: Event<T> = first.filter({ fn });
```

- **Тип**

```ts
event.filter(config: {
  fn(payload: Payload): boolean
}): Event<Payload>
```

- **Примеры**

<Tabs>
<TabItem label="😕 filter">

```js
import { createEvent, createStore } from "effector";

const numbers = createEvent();
const positiveNumbers = numbers.filter({
  fn: ({ x }) => x > 0,
});

const $lastPositive = createStore(0);

$lastPositive.on(positiveNumbers, (n, { x }) => x);

$lastPositive.watch((x) => {
  console.log("последнее положительное:", x);
});

// => последнее положительное: 0

numbers({ x: 0 });
// нет реакции

numbers({ x: -10 });
// нет реакции

numbers({ x: 10 });
// => последнее положительное: 10
```

<br />
[Открыть пример](https://share.effector.dev/H2Iu4iJH)

</TabItem>
<TabItem label="🤩 sample + filter">

```js
import { createEvent, createStore, sample } from "effector";

const numbers = createEvent();
const positiveNumbers = sample({
  clock: numbers,
  filter: ({ x }) => x > 0,
});

const $lastPositive = createStore(0);

$lastPositive.on(positiveNumbers, (n, { x }) => x);

$lastPositive.watch((x) => {
  console.log("последнее положительное:", x);
});

// => последнее положительное: 0

numbers({ x: 0 });
// нет реакции

numbers({ x: -10 });
// нет реакции

numbers({ x: 10 });
// => последнее положительное: 10
```

</TabItem>
</Tabs>

- **Возвращаемое значение**

Возвращает новое производное событие.

---

### `.filterMap(fn)` (#event-methods-filterMap-fn)

:::tip{title="наш любимый sample"}
Этот метод также можно заменить на операцию [`sample`](/ru/api/effector/sample) с аргументами `filter` + `fn`:

```ts
const event = createEvent();

const filteredAndMappedEvent = sample({
  clock: event,
  filter: () => true,
  fn: () => "value",
});
```

:::

Этот метод генерирует новое производное событие, которое **может быть вызвано** после исходного события, но с преобразованным аргументом. Этот специальный метод позволяет одновременно преобразовывать данные и фильтровать срабатывание события.

Этот метод наиболее полезен с API JavaScript, которые иногда возвращают `undefined`.

- **Формула**

```ts
// Событие любого типа, как производное так и обычное
const first: Event<T> | EventCallable<T>;
const second: Event<F> = first.filterMap(fn);
```

- **Тип**

```ts
event.filterMap<T>(fn: (payload: Payload) => T | undefined): Event<T>
```

- **Примеры**

```tsx
import { createEvent } from "effector";

const listReceived = createEvent<string[]>();

// Array.prototype.find() возвращает `undefined`, когда элемент не найден
const effectorFound = listReceived.filterMap((list) => {
  return list.find((name) => name === "effector");
});

effectorFound.watch((name) => console.info("найден", name));

listReceived(["redux", "effector", "mobx"]); // => найден effector
listReceived(["redux", "mobx"]);
```

:::info{title="Внимание"}
Функция `fn` должна возвращать некоторые данные. Если возвращается `undefined`, вызов производного события будет пропущено.
:::

[Открыть пример](https://share.effector.dev/ARDanMAM)

- **Возвращаемое значение**

Возвращает новое производное событие.

---

### `.watch(watcher)` (#event-methods-watch-watcher)

Метод `.watch` вызывается колбэк `watcher` каждый раз при срабатывании события.

:::tip{title="Помните"}
Метод `watch` не обрабатывает и не сообщает о исключениях, не управляет завершением асинхронных операций и не решает проблемы гонки данных.

Его основное предназначение — для краткосрочного отладки и логирования.
:::

[Подробнее в разделе изучения](/ru/essentials/events#event-watch).

- **Формула**

```ts
// Событие любого типа, как производное так и обычное
const event: Event<T> | EventCallable<T>;
const unwatch: () => void = event.watch(fn);
```

- **Тип**

```ts
  event.watch(watcher: (payload: Payload) => any): Subscription
```

- **Примеры**

```js
import { createEvent } from "effector";

const sayHi = createEvent();
const unwatch = sayHi.watch((name) => console.log(`${name}, привет!`));

sayHi("Питер"); // => Питер, привет!
unwatch();

sayHi("Дрю"); // => ничего не произошло
```

[Открыть пример](https://share.effector.dev/9YVgCl4C)

- **Возвращаемое значение**

Возвращает функцию для отмены подписки.

---

### `.subscribe(observer)` (#event-methods-subscribe-observer)

Это низкоуровневый метод для интеграции события со стандартным шаблоном `Observable`.

Подробнее:

- https://rxjs.dev/guide/observable
- https://github.com/tc39/proposal-observable

:::info{title="Помните"}
Вам не нужно использовать этот метод самостоятельно. Он используется под капотом движками рендеринга и так далее.
:::

- **Формула**

```ts
const event = createEvent();

event.subscribe(observer);
```

- **Тип**

```ts
event.subscribe(observer: Observer<Payload>): Subscription
```

- **Примеры**

```ts
import { createEvent } from "effector";

const userLoggedIn = createEvent<string>();

const subscription = userLoggedIn.subscribe({
  next: (login) => {
    console.log("User login:", login);
  },
});

userLoggedIn("alice"); // => User login: alice

subscription.unsubscribe();
userLoggedIn("bob"); // ничего не произойдет
```

## Свойства (#event-properties)

Этот набор свойств в основном задается с помощью [`effector/babel-plugin`](/ru/api/effector/babel-plugin) или [`@effector/swc-plugin`](/ru/api/effector/swc-plugin). Таким образом, они существуют только при использовании Babel или SWC.

### `.sid` (#event-properties-sid)

Это уникальный идентификатор для каждого события.

Важно отметить, что SID не изменяется при каждом запуске приложения, он статически записывается в пакет вашего приложения для абсолютной идентификации юнитов.

Это может быть полезно для отправки событий между рабочими или
сервером/браузером: [examples/worker-rpc](https://github.com/effector/effector/tree/master/examples/worker-rpc).

- **Тип**

```ts
interface Event {
  sid: string | null;
}
```

---

### `.shortName` (#event-properties-shortName)

Это свойство содержащее имя переменной, в которой объявлено событие.

```ts
import { createEvent } from "effector";

const demo = createEvent();
// demo.shortName === 'demo'
```

Но переопределение события в другую переменную ничего не изменит:

```ts
const another = demo;
// another.shortName === 'demo'
```

- **Тип**

```ts
interface Event {
  shortName: string;
}
```

---

### `.compositeName` (#event-properties-compositeName)

Это свойство содержит полную внутреннюю цепочку юнитов. Например, событие может быть создано доменом, поэтому составное имя будет содержать имя домена внутри него.

:::tip{title="Помните"}
Обычно, если требуется длинное имя, лучше передать его явно в поле `name`.
:::

```ts
import { createEvent, createDomain } from "effector";

const first = createEvent();
const domain = createDomain();
const second = domain.createEvent();

console.log(first.compositeName);
// {
//     "shortName": "first",
//     "fullName": "first",
//     "path": [
//         "first"
//      ]
// }

console.log(second.compositeName);
// {
//     "shortName": "second",
//     "fullName": "domain/second",
//     "path": [
//         "domain",
//         "second"
//      ]
// }
```

- **Тип**

```ts
interface Event {
  compositeName: {
    shortName: string;
    fullName: string;
    path: Array<string>;
  };
}
```

## Особенности Event (#event-peculiarities)

1. В Effector любое событие поддерживает только **один аргумент**.
   Вызов события с двумя или более аргументами, как в случае `someEvent(first, second)`, будет игнорировать все аргументы кроме первого.
2. В методах событий нельзя вызывать другие события или эффекты - **функции должны быть чистыми**

## Связанные API и статьи (#related-api-and-docs-to-event)

- **API**
  - [`createEvent`](/ru/api/effector/createEvent) - Создание нового события
  - [`createApi`](/ru/api/effector/createApi) - Создание набора событий для стора
  - [`merge`](/ru/api/effector/merge) - Слияние событий в одно
  - [`sample`](/ru/api/effector/sample) - Ключевой оператор для построения связей между юнитами
- **Статьи**
  - [Как работать с событиями](/ru/essentials/events)
  - [Как мыслить в effector и почему события важны](/ru/resources/mindset)
  - [Гайд по типизации событий и юнитов](/ru/essentials/typescript#typing-events)
